package arrayutil

import (
	"sort"
)

type AnyList struct {
	list []interface{}
}

// 添加, 如果存在, 不处理
func (arr *AnyList) Add(items ...interface{}) {
	for _, item := range items {
		if arr.Contains(item) {
			return
		}
		arr.Push(item)
	}
}

// 添加, 如果存在, 不处理
func (arr *AnyList) AddConf(cond func(item interface{}) bool, items ...interface{}) {
	for _, item := range items {
		if arr.ContainsCond(cond) {
			return
		}
		arr.Push(item)
	}
}

func (arr *AnyList) Set(index int, val interface{}) {
	arr.list[index] = val
}

func (arr *AnyList) SetList(val []interface{}) {
	arr.list = val
}

func (arr *AnyList) At(index int) interface{} {
	if index < 0 {
		return nil
	}
	if index > arr.Length() {
		return nil
	}
	return arr.list[index]
}

func (arr *AnyList) Clear() {
	//*arr = (*arr)[:0]
	arr.list = []interface{}{}
}

func (arr *AnyList) Dispose() {
	arr.list = nil
}

func (arr *AnyList) Clone() *AnyList {
	s := arr.list
	ss := make([]interface{}, len(s), cap(s))
	copy(ss, s)

	return &AnyList{list: ss}
}

func (arr *AnyList) Contains(item interface{}) bool {
	return arr.IndexOf(item) != -1
}

func (arr *AnyList) ContainsCond(cond func(item interface{}) bool) bool {
	return arr.IndexOfConf(cond) != -1
}

// 按照条件计数
func (arr *AnyList) CountCond(cond func(item interface{}) bool) int {
	c := 0
	s := arr.list
	for i := 0; i < len(s); i++ {
		if cond(s[i]) {
			c++
		}
	}
	return c
}

// 每一个项都符合条件就返回true
func (arr *AnyList) Every(cond func(item interface{}) bool) bool {
	s := arr.list
	for i := 0; i < len(s); i++ {
		val := s[i]
		if cond(val) == false {
			return false
		}
	}
	return true
}

func (arr *AnyList) First(cond func(item interface{}) bool) (val interface{}, has bool) {
	s := arr.list
	for i := 0; i < len(s); i++ {
		v := s[i]
		if cond(v) {
			return v, true
		}
	}
	return nil, false
}

func (arr *AnyList) Filter(cond func(item interface{}) bool) *AnyList {
	var a []interface{}
	for _, x := range arr.list {
		if cond(x) {
			a = append(a, x)
		}
	}
	return &AnyList{list: a}
}

func (arr *AnyList) ForRange(handler func(item interface{})) {
	s := arr.list
	ss := make([]interface{}, len(s), cap(s))
	copy(ss, s)

	for _, x := range ss {
		a := x
		handler(a)
	}
}

func (arr *AnyList) IndexOfConf(cond func(item interface{}) bool) int {
	s := arr.list
	for i := 0; i < len(s); i++ {
		if cond(s[i]) {
			return i
		}
	}
	return -1
}

func (arr *AnyList) IndexOf(item interface{}) int {
	s := arr.list
	for i := 0; i < len(s); i++ {
		if s[i] == item {
			return i
		}
	}
	return -1
}

func (arr *AnyList) Last(cond func(item interface{}) bool) interface{} {
	s := arr.list
	for i := len(s) - 1; i >= 0; i-- {
		val := s[i]
		if cond(val) {
			return val
		}
	}
	return nil
}

func (arr *AnyList) Length() int {
	return len(arr.list)
}

func (arr *AnyList) Pop() interface{} {
	s := arr.list
	last := s[len(s)-1]
	s[len(s)-1] = nil // GC
	s2 := s[:len(s)-1]
	arr.list = s2

	return last
}

func (arr *AnyList) Push(item interface{}) {
	s := arr.list
	s = append(s, item)
	arr.list = s
}

func (arr *AnyList) PushList(list *AnyList) {
	s := arr.list
	s = append(s, list.list...)
	arr.list = s
}

func (arr *AnyList) Remove(item interface{}) {
	i := arr.IndexOf(item)
	if i != -1 {
		arr.RemoveAt(i)
	}
}

func (arr *AnyList) RemoveAt(i int) {
	s := arr.list
	copy(s[i:], s[i+1:])
	s[len(s)-1] = nil // GC
	s2 := s[:len(s)-1]
	arr.list = s2
}

func (arr *AnyList) Replace(i int, item interface{}) {
	s := arr.list
	over := i - len(s)
	if over > -1 {
		ss := make([]interface{}, i+1)
		copy(ss[0:], s[:])
		s = ss
	}
	s[i] = item
	arr.list = s
}

func (arr *AnyList) Reverse() {
	s := arr.list
	for i := len(s)/2 - 1; i >= 0; i-- {
		opp := len(s) - 1 - i
		s[i], s[opp] = s[opp], s[i]
	}
}

func (arr *AnyList) Shift() interface{} {
	s := arr.list
	top := s[0]
	s[0] = nil // GC
	s2 := s[1:]
	arr.list = s2

	return top
}

func (arr *AnyList) Slice() []interface{} {
	return arr.list
}

func (arr *AnyList) Sort(compare func(a, b interface{}) int) {
	l := arr.list
	sort.Slice(l, func(i, j int) bool {
		return compare(l[i], l[j]) >= 0
	})
}

func (arr *AnyList) Unshift(item interface{}) {
	s := arr.list
	l := len(s) + 1
	ss := make([]interface{}, l, l)
	ss[0] = item
	copy(ss[1:], s[:])
	arr.list = ss
}

// 去重操作, 返回去重后的数组
func (arr *AnyList) Unique() *AnyList {
	var r []interface{}
	l := arr.list
	m := map[interface{}]struct{}{} // 存放不重复主键
	for _, e := range l {
		length := len(m)
		m[e] = struct{}{}
		if len(m) != length { // 加入map后，map长度变化，则元素不重复
			r = append(r, e)
		}
	}
	return &AnyList{list: r}
}

// 去重操作, 返回去重后的数组
// 自定义键值
func (arr *AnyList) UniqueByCustomKey(getKey func(item interface{}) string) *AnyList {
	var r []interface{}
	l := arr.list
	m := map[string]struct{}{} // 存放不重复主键
	for _, e := range l {
		length := len(m)
		m[getKey(e)] = struct{}{}
		if len(m) != length { // 加入map后，map长度变化，则元素不重复
			r = append(r, e)
		}
	}
	return &AnyList{list: r}
}

// 并集
func (arr *AnyList) Union(a *AnyList, getKey func(a interface{}) string) *AnyList {
	arr.PushList(a)
	return arr.Unique()
}

// 并集
func (arr *AnyList) UnionByCustomKey(a *AnyList, getKey func(a interface{}) string) *AnyList {
	arr.PushList(a)
	return arr.UniqueByCustomKey(getKey)
}
